package com.tao.utils;

/**
 * reate by tao on{DATE}
 * <p>
 * <p>
 * ReflectUtil.java
 * 描述：反射工具类
 * <p>
 * 当前版本：1.0
 * <p>
 * 创建时间：***
 * 作者: Lee
 * <p>
 * <p>
 * ReflectUtil.java
 * 描述：反射工具类
 * <p>
 * 当前版本：1.0
 * <p>
 * 创建时间：***
 * 作者: Lee
 * <p>
 * <p>
 * ReflectUtil.java
 * 描述：反射工具类
 * <p>
 * 当前版本：1.0
 * <p>
 * 创建时间：***
 * 作者: Lee
 * <p>
 * <p>
 * ReflectUtil.java
 * 描述：反射工具类
 * <p>
 * 当前版本：1.0
 * <p>
 * 创建时间：***
 * 作者: Lee
 * <p>
 * <p>
 * ReflectUtil.java
 * 描述：反射工具类
 * <p>
 * 当前版本：1.0
 * <p>
 * 创建时间：***
 * 作者: Lee
 * <p>
 * <p>
 * ReflectUtil.java
 * 描述：反射工具类
 * <p>
 * 当前版本：1.0
 * <p>
 * 创建时间：***
 * 作者: Lee
 */
/**
 *
 * ReflectUtil.java
 * 描述：反射工具类
 *
 * 当前版本：1.0
 *
 * 创建时间：***
 * 作者: Lee
 */


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class ReflectUtil {
    /**
     * 直接获取对象属性值
     * @param obj            对象实例
     * @param fieldName        属性名称
     * @return
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        if (obj == null) return null;
        Object value = null;
        Field[] fields = obj.getClass().getDeclaredFields();
        for (int j = 0; j < fields.length; j++) {
            if (fields[j].getName().equals(fieldName)) {
                fields[j].setAccessible(true);
                // 字段值  
                try {
                    value = fields[j].get(obj);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        return value;
    }

    /**
     * 通过get方法获取值
     * @param obj                实例对象
     * @param fieldName            属性名称
     * @param parameterTypes    函数的参数
     * @return
     */
    public static Object getFieldValueByMethod(Object obj, String fieldName, Class<?>... parameterTypes) {
        if (obj == null) return null;
        Object value = null;

        try {
            Method method = obj.getClass().getMethod(fieldGetMethodName(fieldName));
            value = method.invoke(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return value;
    }

    private static String fieldGetMethodName(String fieldName) {
        String getMethod = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        return getMethod;
    }

    /**
     * 设置值，包括key中间"."的情况
     * @param object
     * @param key
     * @param value
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static void setValue(Object object, String key, Object value) {

        //用来处理多数据问题
        Object oldObj = object;

        Object obj = object;
        String attr = null;
        while (key.indexOf(".") != -1) {
            attr = key.substring(0, key.indexOf("."));
            key = key.substring(key.indexOf(".") + 1);
            if (obj instanceof Map) {
                obj = ((Map) obj).get(attr);
            }
            if (obj instanceof List) {
                for (Object o : (List<?>) oldObj) {
                    if (o instanceof Map) {
                        obj = ((Map) o).get(attr);
                    } else {
                        obj = getFieldValue(o, attr);
                    }
                }
            } else {
                obj = getFieldValue(obj, attr);
            }
        }

        if (obj != null) {

            if (obj instanceof Map) {
                if (oldObj instanceof List) {
                    for (Object o : (List<?>) oldObj) {
                        if (obj instanceof Map) {
                            if (attr != null) {
                                o = getFieldValue(o, attr);
                                ((Map) o).put(key, value);
                            }
                        } else {
                            setFieldValue(o, key, value);
                        }
                    }
                } else {
                    ((Map) obj).put(key, value);
                }

            } else {
                if (oldObj instanceof List) {
                    for (Object o : (List<?>) oldObj) {
                        if (obj instanceof Map) {
                            if (attr != null) {
                                o = getFieldValue(o, attr);
                                ((Map) o).put(key, value);
                            }
                        } else {
                            setFieldValue(o, key, value);
                        }
                    }
                } else {
                    setFieldValue(obj, key, value);
                }
            }
        }
    }

    /**
     * 设置值
     * @param obj
     * @param fieldName
     * @param val
     * @return
     */
    public static Object setFieldValue(Object obj, String fieldName, Object val) {
        if (obj == null) return null;
        Field[] fields = obj.getClass().getDeclaredFields();
        for (int j = 0; j < fields.length; j++) {
            if (fields[j].getName().equals(fieldName)) {
                fields[j].setAccessible(true);
                // 字段值  
                try {
                    String type = fields[j].getType().getSimpleName();
                    //System.out.println("type : " + type);

                    if (val instanceof String) {
                        String value = val.toString();
                        if ("int".equals(type)) {
                            if (!StringUtil.isEmpty(value)) {
                                fields[j].setInt(obj, Integer.valueOf(value));
                            }
                        } else if ("long".equals(type)) {
                            if (!StringUtil.isEmpty(value)) {
                                fields[j].setLong(obj, Long.valueOf(value));
                            }
                        } else if ("double".equals(type)) {
                            if (!StringUtil.isEmpty(value)) {
                                fields[j].setDouble(obj, Double.valueOf(value));
                            }
                        } else if ("float".equals(type)) {
                            if (!StringUtil.isEmpty(value)) {
                                fields[j].setFloat(obj, Float.valueOf(value));
                            }
                        } else if ("Integer".equals(type)) {
                            if (StringUtil.isLong(value)) {
                                fields[j].set(obj, Integer.valueOf(value));
                            } else {
                                fields[j].set(obj, null);
                            }
                        } else if ("Long".equals(type)) {
                            if (StringUtil.isLong(value)) {
                                fields[j].set(obj, Long.valueOf(value));
                            } else {
                                fields[j].set(obj, null);
                            }
                        } else if ("Float".equals(type)) {
                            if (StringUtil.isFloat(value)) {
                                fields[j].set(obj, Float.valueOf(value));
                            } else {
                                fields[j].set(obj, null);
                            }
                        } else if ("Double".equals(type)) {
                            if (StringUtil.isDouble(value)) {
                                fields[j].set(obj, Double.valueOf(value));
                            } else {
                                fields[j].set(obj, null);
                            }
                        } else {
                            fields[j].set(obj, val);
                        }
                    } else {
                        fields[j].set(obj, val);
                    }

                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        return val;
    }

    /**
     * 是否存在该属性
     * @param obj  对象实例
     * @param fieldName  属性名
     * @return
     */
    public static boolean isExistField(Object obj, String fieldName) {
        boolean r = false;
        if (obj != null) {
            Field[] fields = obj.getClass().getDeclaredFields();
            for (int j = 0; j < fields.length; j++) {
                if (fields[j].getName().equals(fieldName)) {
                    r = true;
                    break;
                }
            }
        }

        return r;
    }

    public static Object callMethod(Object obj, String methodName) {
        return callMethod(obj, methodName, null);
    }

    public static Object callMethod(Object obj, String methodName, Class<?>[] params, Object... args) {
        try {

            Method method = getMethod(obj, methodName, params);

            if (method == null)
                return false;

            method.setAccessible(true);
            if (args == null) {
                return method.invoke(obj);

            } else {
                return method.invoke(obj, args );
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return false;

    }

    private static Method getMethod(Object obj, String methodName, Class<?>... params) {
        Class aClass = obj.getClass();
        while (aClass != null) {
            try {

                Method[] declaredMethods1 = aClass.getDeclaredMethods();
                for (Method method1 : declaredMethods1) {
                    if (method1.getName().equals(methodName)){
                        Type[] genericParameterTypes = method1.getGenericParameterTypes();
                        if (params ==null && (genericParameterTypes ==null ||genericParameterTypes.length==0))return method1;
                        
                        if (genericParameterTypes.length == params.length){
                            boolean eq =true ;
                            for (int i = 0; i < genericParameterTypes.length; i++) {
                                Type parameterType = genericParameterTypes[i];
                                if (parameterType instanceof  Class){
                                    
                                    if (!isParentClass((Class) parameterType, params[i])){
                                        eq =false;
                                        break;
                                    }
                                }
                            }
                            if (eq)
                                return method1;
                        }
                    }
                }

            }  catch (SecurityException   e) {
                e.printStackTrace();
            }
            if (aClass.getName().equals(Object.class.getName()))
                aClass = null;
            else
                aClass = aClass.getSuperclass();
        }
        return null;
    }

    private static boolean isParentClass(Class parameterType, Class<?> param) {
        boolean is = param.getName().equals(parameterType.getName());
        while (!is){
            param = param.getSuperclass();
            is = param.getName().equals(parameterType.getName());
            if (param.getName().equals(Object.class.getName()))break;
        }
        return is;
    }

    static class StringUtil {


        public static boolean isEmpty(String value) {
            return value != null && !value.isEmpty();
        }

        public static boolean isLong(String value) {
            try {
                Long.parseLong(value);
                return true;
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
            return false;
        }

        public static boolean isDouble(String value) {
            try {
                Double.parseDouble(value);
                return true;
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
            return false;
        }

        public static boolean isFloat(String value) {
            try {
                Float.parseFloat(value);
                return true;
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
            return false;
        }
    }
}

